react.js

您所在的位置:网站首页 react 函数组件 重新渲染 react.js

react.js

2024-02-21 01:23| 来源: 网络整理| 查看: 265

对于函数组件是否需要再次渲染,可以根据 Reacmo 与 React.useMemo 来优化。

函数组件优化 - ReacmoReacmo

Reacmo(ReactNode, [(prevProps, nextProps) => {}])

第一个参数:组件第二个参数【可选】:自定义比较函数。两次的 props 相同的时候返回 true,不同则返回 false。返回 true 会阻止更新,而返回 false 则重新渲染。

如果把组件包装在 Reacmo 中调用,那么组件在相同 props 的情况下渲染相同的结果,以此通过记忆组件渲染结果的方式来提高组件的性能表现。

Reacmo 仅检查 props 变更,默认情况下其只会对复杂对象做浅层对比,如果想要控制对比过程,那么请将自定义的比较函数通过第二个参数传入来实现。

const MyComponent = Reacmo(function MyComponent(props) { /* 使用 props 渲染 */ }, (prevProps, nextProps) => { /* 如果把 nextProps 传入 render 方法的返回结果与 将 prevProps 传入 render 方法的返回结果一致则返回 true, 否则返回 false */ })结论

当父组件重新渲染时:

子组件未使用 Reacmo,不管子组件 props 是什么类型,子组件都会重复渲染;

子组件使用 Reacmo,并且不传入第二个参数

当子组件的 props 是基础类型,子组件不会重复渲染;当子组件的 props 是引用类型,如果 props 未使用对应的 hook,那么会重复渲染,并且子组件多一次 diff 计算。如果使用对应的 hook,不会重复渲染;子组件使用 Reacmo,并且自定义对比函数,子组件是否重复渲染由自定义函数决定;测试

背景介绍

在一个父组件里有两个子组件,当父组件发生重新渲染时,两个子组件在不同的条件控制下是否会重新渲染?

字段解释

字段名含义测试意义title基础类型常量测试基础类型改变对子组件的影响commonObject引用类型常量测试引用类型改变对子组件的影响;测试 hook(useMemo) 定义的引用类型改变对子组件的影响dataSourceuseState 定义的引用类型测试 hook(useState) 定义的引用类型改变对子组件的影响updateXxxxInfo方法测试引用类型改变对子组件的影响;测试 hook(useCallBack) 定义的引用类型改变对子组件的影响

基础代码

子组件 BaseInfo:

const BaseInfo = (props) => { console.log('BaseInfo 重新渲染, props:', props) const { title, dataSource = {} } = props return ( 姓名:{dataSource.name} ) }

子组件 OtherInfo:

const OtherInfo = (props) => { console.log('OtherInfo 重新渲染, props:', props) const { title, dataSource } = props return ( 学校:{dataSource.school} ) }

父组件 FunctionTest:

function FunctionTest() { const [baseInfo, setBaseInfo] = useState({ name: '混沌' }) const [otherInfo, setOtherInfo] = useState({ school: '上海大学' }) return ( { console.log('点击-修改基本信息') setBaseInfo({ name: '貔貅' }) }} >修改基本信息 { console.log('点击-修改其他信息') setOtherInfo({ school: '北京大学' }) }} >修改其他信息 ) }测试一:修改子组件 BaseInfo 为 Reacmo 包裹const BaseInfo = Reacmo((props) => { console.log('BaseInfo 重新渲染, props:', props) const { title, dataSource = {} } = props return ( 姓名:{dataSource.name} ) })

点击“修改基本信息”后,BaseInfo 与 OtherInfo 全部重新渲染。点击“修改其他信息”后,OtherInfo 重新渲染,BaseInfo 没有重新渲染。

结论:

当 props 是基本类型或 react hook(useState) 定义的引用类型时,使用 Reacmo 可以阻止重复渲染。使用了 Reacmo 的 BaseInfo,当在 props 相同时没有重复渲染。测试二:在测试一的基础上,在父组件 FunctionTest 中添加引用类型,并传给两个子组件

测试2.1: 当引用类型的常量是一个对象/数组时

function FunctionTest() { //... const commonObject = {} //... return ( // ... // ... ) }

点击“修改基本信息”或“修改其他信息”,BaseInfo 与 OtherInfo 全部重新渲染。

测试2.2: 当引用类型的常量是一个方法时:

function FunctionTest() { //... const updateBaseInfo = () => { console.log('更新基本信息,原数据:', baseInfo) setBaseInfo({ name: '饕餮' }) } const updateOtherInfo = () => { console.log('更新其他信息,原数据:', otherInfo) setOtherInfo({ school: '河南大学' }) } //... return ( //... //... ) }

点击“修改基本信息”或“修改其他信息”,BaseInfo 与 OtherInfo 全部重新渲染。

结论:

当 props 包含引用类型时,使用 Reacmo 并且不自定义比较函数时不能阻止重复渲染。无论有没有使用 Reacmo 都会重新渲染,此时 BaseInfo 性能不如 OtherInfo, 因为 BaseInfo 多了一次 diff。测试三:在测试二的基础上,添加 hook

测试3.1:给 commonObject 添加 useMemo hook

const commonObject = useMemo(() => {}, [])

点击“修改基本信息”后,BaseInfo 与 OtherInfo 全部重新渲染。点击“修改其他信息”后,OtherInfo 重新渲染,BaseInfo 没有重新渲染。

测试3.2: 给 updateBaseInfo 与 updateOtherInfo 添加 useCallback hook

const updateBaseInfo = useCallback(() => { console.log('更新基本信息,原数据:', baseInfo) setBaseInfo({ name: '饕餮' }) }, []) const updateOtherInfo = useCallback(() => { console.log('更新其他信息,原数据:', otherInfo) setOtherInfo({ school: '河南大学' }) }, [])

点击“修改基本信息”后,BaseInfo 与 OtherInfo 全部重新渲染。点击“修改其他信息”后,OtherInfo 重新渲染,BaseInfo 没有重新渲染。

结论:

当 props 的函数使用 useMemo/useCallback 时,使用 Reacmo 并且不自定义比较函数时可以阻止重复渲染。使用了 Reacmo 的 BaseInfo,当在 props 相同时没有重复渲染。测试四:在测试三的基础上,给 OtherInfo 添加 Reacmo 并且自定义比较函数const OtherInfo = Reacmo((props) => { console.log('OtherInfo 重新渲染, props:', props) const { title, dataSource, updateOtherInfo } = props return ( 学校:{dataSource.school} 更新学校 ) }, (prevProps, nextProps) => { console.log('OtherInfo props 比较') console.log('OtherInfo 老的props:', prevProps) console.log('OtherInfo 新的props:', nextProps) let flag = true Object.keys(nextProps).forEach(key => { let result = nextProps[key] === prevProps[key] console.log(`比较 ${key}, 结果是:${result}`) if (!result) { flag = result } }) console.log(`OtherInfo 组件${flag ? '不会' : '会'}渲染`) return flag })

点击“修改基本信息”后,BaseInfo 重新渲染, OtherInfo 没有重新渲染。点击“修改其他信息”后,BaseInfo 没有重新渲染,OtherInfo 重新渲染。

结论:

当 props 的函数使用 useMemo/useCallback 时,使用 Reacmo 并且不自定义比较函数时可以阻止重复渲染。Reacmo 的第二个参数可以判断是否需要自定义渲染。函数组件优化 - React.useMemoReact.useMemo

React.useMemo(() => {}, [])

返回一个 memoized 值。

把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。

结论

当父组件重新渲染时:

子组件未使用 React.useMemo,不管子组件 props 是什么类型,子组件都会重复渲染;子组件使用 React.useMemo,依赖项数组的值有改变时会造成子组件重复渲染;测试

Reacmo 默认是对 props 浅比较,React.useMemo 是对依赖项数组浅比较,所以针对不同的参数比较结果相同【这里就不详细介绍了】。

引用类型的参数建议使用 useState, useMemo,useCallback 等hooks,否则浅比较结果不同。


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3